home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#50 (Nov 89)
/
Inside Code
/
MeterMain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-30
|
37KB
|
1,229 lines
/* MeterMain.c - test rig for designing meters, illustrating the interaction
between documents, windows, and controls
by Ken Earle, 1989
ThinkC 3.0 settings:
Options...; <MacHeaders>, Check Pointers, Require Protoypes
Set Project Type...; File Type APPL, Creator whatever
Files: MacTraps
Math
Meter.c MeterMain.c
Headers: <MacHeaders> <math.h> "Meter.h"
Resources: none (What? Blasphemy!)
*/
#include "Meter.h"
#define APPLEID 15
#define FILEID 16
#define EDITID 17
#define QUIT 12
#define HSCROLL 1L /* scroll bar ID */
#define VSCROLL 2L
#define SCROLLSIZE 15
#define DOCHEIGHT 720 /* 10" x 72 */
#define DOCWIDTH 576 /*8" x 72 */
#define MAXWINDOWWIDTH (DOCWIDTH + SCROLLSIZE)
#define MAXWINDOWHEIGHT (DOCHEIGHT + SCROLLSIZE)
#define DISPLAYBOXWIDTH 72 /* <= 0 removes the display
and disables DrawDisplayBox() */
/* display modes are used by DrawDisplayBox() */
enum DisplayMode
{
forWindow, forMeter, forThumb, forDebug = 300 /* forces to 16-bit size */
};
typedef enum DisplayMode DisplayMode;
/* useful globals */
WindowRecord wRecord1, wRecord2;
RgnHandle updateRgn;
MenuHandle appleMenu, fileMenu, editMenu;
/* handy globals */
Rect dragRect = { 0, 0, 1024, 1024 };
char wTitle1[] = "\PRear Window";
char wTitle2[] = "\PFront Window";
char mTitle1[] = "\PFirst Meter";
char mTitle2[] = "\PSecond Meter";
char mTitle3[] = "\PThird Meter";
char mTitle4[] = "\PFourth Meter";
/* Prototypes for functions defined in this file */
int main(void);
void DoStandardInits(void);
void MakeMenus(void);
Boolean DoMenu(long);
void MakeTwoWindows(void);
void MakeTwoMeters(WindowPtr, int);
void DitherMeters(void);
void DoContent(WindowPtr, EventRecord*);
void UpdateContents(WindowPtr, Boolean);
void DrawDisplayBox(WindowPtr, void**, DisplayMode, int, int);
void DoZoomWindow (WindowPtr, int);
void DoGrowWindow(EventRecord*);
void DoCloseWindow(void);
Boolean AMeterWindow(WindowPtr);
void GetScrollHandles(WindowPtr, ControlHandle*, ControlHandle*);
void LocalToDoc(Point*);
void MeterProc(MeterHandle, int);
pascal void ScrollProc(ControlHandle,int);
void ThumbControl(ControlHandle, Point);
void PutMetersOnClip(WindowPtr);
main()
{
int part;
EventRecord myEvent;
WindowPtr whichWindow;
GrafPtr savePort;
MeterHandle mH;
ControlHandle cH;
Rect cRect; /* see "activateEvt" */
RgnHandle tempRgn; /* see updateEvt */
Boolean quitting = FALSE;
DoStandardInits();
updateRgn = NewRgn();
MakeMenus();
MakeTwoWindows();
do /* while not quitting */
{
do /* while no next event */
{
SystemTask();
DitherMeters();
} while (!GetNextEvent(everyEvent, &myEvent));
switch (myEvent.what)
{
case mouseDown:
switch (part = FindWindow( myEvent.where, &whichWindow ))
{
case inDesk:
SysBeep(2);
break;
case inMenuBar:
quitting = DoMenu(MenuSelect(myEvent.where));
case inSysWindow:
SystemClick( &myEvent, whichWindow );
break;
case inDrag:
if (AMeterWindow(whichWindow))
DragWindow( whichWindow, myEvent.where, &dragRect );
break;
case inZoomIn:
case inZoomOut:
if (AMeterWindow(whichWindow))
if (TrackBox(whichWindow, myEvent.where, part))
DoZoomWindow (whichWindow, part);
break;
case inGrow:
if (AMeterWindow(whichWindow))
DoGrowWindow(&myEvent);
break;
case inGoAway:
if (AMeterWindow(whichWindow))
if (TrackGoAway (whichWindow, myEvent.where))
DoCloseWindow();
break;
case inContent:
if (whichWindow != FrontWindow())
SelectWindow(whichWindow);
else
if (AMeterWindow(whichWindow))
DoContent(whichWindow, &myEvent);
break;
default:
break;
} /* switch FindWindow */
break;
case keyDown:
case autoKey:
break;
case activateEvt:
whichWindow = (WindowPtr)myEvent.message;
if (AMeterWindow(whichWindow))
{
mH = (MeterHandle)(((WindowPeek)whichWindow)->refCon);
cH = ((WindowPeek)whichWindow)->controlList;
if ( myEvent.modifiers & activeFlag )
{
SetPort(whichWindow);
ClipRect(&(whichWindow->portRect));
InvalRect(&(whichWindow->portRect));
DrawGrowIcon(whichWindow);
if (cH)
{
while (cH)
{
ShowControl(cH);
cRect = (**cH).contrlRect;
ValidRect(&cRect);
cH = (**cH).nextControl;
}
}
if (ValidMeter(mH))
{
while (mH)
{
/* activate meters */
(**mH).meterHilite = 0;
mH = (**mH).nextMeter;
}
}
cRect = thePort->portRect;
cRect.bottom -= SCROLLSIZE;
cRect.right -= SCROLLSIZE;
ClipRect(&cRect);
} /* if activate */
else
{
GetPort(&savePort);
SetPort(whichWindow);
ClipRect(&(whichWindow->portRect));
InvalRect(&(whichWindow->portRect));
DrawGrowIcon(whichWindow);
if (cH)
{
while(cH)
{
HideControl(cH);
cH = (**cH).nextControl;
}
}
if (ValidMeter(mH))
{
while (mH)
{
/* deactivate meters */
(**mH).meterHilite = 255;
mH = (**mH).nextMeter;
}
}
SetPort(savePort);
} /* else deactivate */
} /* if our window */
break;
case updateEvt:
whichWindow = (WindowPtr)myEvent.message;
if (AMeterWindow(whichWindow))
{
GetPort(&savePort);
SetPort( whichWindow );
ClipRect(&whichWindow->portRect);
BeginUpdate( whichWindow );
EraseRect(&whichWindow->portRect);
DrawGrowIcon(whichWindow);
DrawControls(whichWindow);
DrawDisplayBox(whichWindow, 0L, forWindow,0,0);
/* Take the scrolls out of updateRgn, because
UpdateContents() sets the clip region to the
(global) updateRgn. */
CopyRgn(whichWindow->visRgn,updateRgn);
tempRgn = NewRgn();
SetRectRgn(tempRgn, whichWindow->portRect.left,
whichWindow->portRect.bottom - SCROLLSIZE,
whichWindow->portRect.right,
whichWindow->portRect.bottom);
DiffRgn(updateRgn, tempRgn, updateRgn);
SetRectRgn(tempRgn, whichWindow->portRect.right - SCROLLSIZE,
whichWindow->portRect.top,
whichWindow->portRect.right,
whichWindow->portRect.bottom - SCROLLSIZE);
DiffRgn(updateRgn, tempRgn, updateRgn);
DisposeRgn(tempRgn);
/* Redraw the "true contents" of the window. */
UpdateContents(whichWindow, (whichWindow == FrontWindow()));
EndUpdate( whichWindow );
SetPort(savePort);
}
break;
default:
break;
} /* switch myEvent.what */
} while (!quitting);
if (FrontWindow())
PutMetersOnClip(FrontWindow());
} /* end main() */
void DoStandardInits()
{
MoreMasters();
MoreMasters();
MoreMasters();
InitGraf(&thePort);
InitFonts();
FlushEvents(everyEvent, 0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(0L);
InitCursor();
}/* end DoStandardInits() */
void MakeMenus()
{
appleMenu = NewMenu(APPLEID,"\P\24");
AppendMenu(appleMenu,"\P(About nothing...;(-");
AddResMenu(appleMenu,'DRVR');
InsertMenu(appleMenu,0);
fileMenu = NewMenu(FILEID,"\PFile");
AppendMenu(fileMenu,"\PNew;Open...;(-;Close;Save;Save as...;Revert;(-;Page Setup...;Print...;(-;Quit/Q");
InsertMenu(fileMenu,0);
editMenu = NewMenu(EDITID,"\PEdit");
AppendMenu(editMenu,"\PUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;(-;Show Clipboard;Select All");
InsertMenu(editMenu,0);
DrawMenuBar();
} /* end MakeMenus() */
/* DoMenu returns TRUE when quit selected */
Boolean DoMenu(menuAndItem)
long menuAndItem;
{
int theItem;
char name[64];
theItem = LoWord(menuAndItem);
switch (HiWord(menuAndItem))
{
case APPLEID:
if (theItem > 1)
{
if (FrontWindow())
PutMetersOnClip(FrontWindow());
GetItem(appleMenu, theItem, name);
OpenDeskAcc(name);
}
break;
case FILEID:
if (theItem == QUIT)
return(TRUE);
break;
case EDITID:
break;
default:
break;
}
HiliteMenu(0);
return(FALSE);
} /* end DoMenu() */
/* Make two windows right off the bat, each with a couple of scroll bars
and a couple of meters. The windows are sized to fit the screen, but limited
to a maximum size of 8" by 10" to show the slight complications that arise when
dealing with a fixed document size. The trick thereafter is to ensure that you
never stray outside the document - see DoGrowWindow() etc */
void MakeTwoWindows()
{
int i, topGap, winWidth, winHeight;
int horRange, vertRange;
Rect boundsRect, cRect, clpRect;
WindowPtr wPtr;
ControlHandle cH;
WStateData *wsd;
/* Old small screen, or something bigger?
topGap = menu bar height + 20 for the window frame */
if ((screenBits.bounds.bottom - screenBits.bounds.top) < 343)
topGap = MBarHeight + 20;
else
topGap = 60;
/* topGap + window height + all offsets(1 here) + 4(at the bottom) = screen height */
winHeight = ((screenBits.bounds.bottom - screenBits.bounds.top - topGap - 14) <= MAXWINDOWHEIGHT) ?
(screenBits.bounds.bottom - screenBits.bounds.top - topGap - 14) : MAXWINDOWHEIGHT;
winWidth = ((screenBits.bounds.right - screenBits.bounds.left - 18) <= MAXWINDOWWIDTH) ?
(screenBits.bounds.right - screenBits.bounds.left - 18) : MAXWINDOWWIDTH;
SetRect(&boundsRect, 4, topGap, 4 + winWidth, topGap + winHeight);
/* Scroll bar ranges: range = amount of document left unseen (honest!) */
vertRange = MAXWINDOWHEIGHT - (boundsRect.bottom - boundsRect.top);
vertRange = (vertRange > 0) ? vertRange : 0;
horRange = MAXWINDOWWIDTH - (boundsRect.right - boundsRect.left);
horRange = (horRange > 0) ? horRange : 0;
/* Create two windows, offset slightly */
for (i = 1; i <= 2; ++i)
{
if (i == 1)
wPtr = NewWindow(&wRecord1, &boundsRect, wTitle1, TRUE, 8,-1L,TRUE, 0L);
else
{
OffsetRect(&boundsRect, 10, 10);
wPtr = NewWindow(&wRecord2, &boundsRect, wTitle2, TRUE, 8,-1L,TRUE, 0L);
}
SetPort(wPtr);
ClipRect(&(thePort->portRect));
/* Adjust zoom rectangles since document size is fixed. */
wsd = (WStateData*)*(((WindowPeek)wPtr)->dataHandle);
wsd->stdState = boundsRect;
wsd->userState = boundsRect;
/* horizontal bar */
/* Note room is reserved at right of the bar for the
display box - see DrawDisplayBox(). */
cRect.top = thePort->portRect.bottom - SCROLLSIZE;
cRect.left = thePort->portRect.left - 1;
cRect.bottom = thePort->portRect.bottom + 1;
cRect.right = thePort->portRect.right - DISPLAYBOXWIDTH - 14;
cH = NewControl(thePort,&cRect,"\P",TRUE,0,0,horRange,scrollBarProc,HSCROLL);
if (horRange == 0)
HiliteControl(cH, 255);
/* vertical bar */
cRect.top = thePort->portRect.top - 1;
cRect.left = thePort->portRect.right - SCROLLSIZE;
cRect.bottom = thePort->portRect.bottom - 14;
cRect.right = thePort->portRect.right + 1;
cH = NewControl(thePort,&cRect,"\P",TRUE,0,0,vertRange,scrollBarProc,VSCROLL);
if (vertRange == 0)
HiliteControl(cH, 255);
clpRect = thePort->portRect;
clpRect.bottom -= SCROLLSIZE;
clpRect.right -= SCROLLSIZE;
ClipRect(&clpRect);
MakeTwoMeters(wPtr, i);
}
}/* end MakeTwoWindows() */
/* Create four meters, two in each window. Note that it is not necessary to
carry around all the meterhandles as globals since they are attached to the
window's refCon field as a linked list by NewMeter(). */
void MakeTwoMeters(wPtr, which)
WindowPtr wPtr;
int which;
{
Rect boundsRect;
MeterHandle mH;
if (which == 1)
{
boundsRect.top = 0;
boundsRect.left = 0;
boundsRect.bottom = 0;
boundsRect.right = 144; /* 2 inches wide */
mH = NewMeter(wPtr, &boundsRect, mTitle1, FALSE, 256L, 0L, 512L, 0L);
(**mH).meterVis = TRUE;
(**mH).meterHilite = 255;
boundsRect.left = 150;
boundsRect.right = 222; /* 1 inch wide */
mH = NewMeter(wPtr, &boundsRect, mTitle2, FALSE, 0L, -1000L, 1000L, 0L);
(**mH).meterVis = TRUE;
(**mH).meterHilite = 255;
}
else if (which == 2) /* the front window at first */
{
boundsRect.top = 10;
boundsRect.left = 50;
boundsRect.bottom = 0;
boundsRect.right = 158;
NewMeter(wPtr, &boundsRect, mTitle3, TRUE, 2000L, 0L, 4095L, 0L);
boundsRect.left = 204;
boundsRect.right = 384;
NewMeter(wPtr, &boundsRect, mTitle4, TRUE, 0L, -40950L, 40950L, 0L);
}
}/* end MakeTwoMeters() */
/* Shake the needle around the setpoint to see it move. Affects
all meters in the front window. */
void DitherMeters()
{
static int random = 0;
static long oldVal = 0L;
long val, setVal, posIncrement, newVal;
int direction, docV, docH;
ControlHandle cHH, cHV;
MeterHandle mH = (MeterHandle)(((WindowPeek)thePort)->refCon);
if (ValidMeter(mH))
{
Delay(0L, &newVal);
if (newVal - oldVal > 8L) /* time delay */
{
if (random > 0)
direction = 1;
else if (random < 0)
direction = -1;
else
direction = 0;
oldVal = newVal;
/* get control handles */
GetScrollHandles(thePort, &cHH, &cHV);
/* find where we've scrolled to */
docV = GetCtlValue(cHV);
docH = GetCtlValue(cHH);
/* shift to the right location in the document */
SetOrigin(docH, docV);
OffsetRgn(thePort->clipRgn, docH, docV);
/* run through all the meters for this window */
while (ValidMeter(mH))
{
val = (**mH).needleValue;
setVal = (**mH).meterValue;
posIncrement = ((**mH).meterMax - (**mH).meterMin)/250L;
newVal = val + (setVal - val)/10L + direction*posIncrement;
SetNeedleValue(mH, newVal);
mH = (**mH).nextMeter;
}
SetOrigin(0, 0);
OffsetRgn(thePort->clipRgn, -docH, -docV);
++random;
if (random >= 5)
random = -5;
}
}
}/* end DitherMeters() */
/* Handle Mouse down in our window - can hit scroll bars or meters. */
void DoContent(theWindow, theEvent)
WindowPtr theWindow;
EventRecord *theEvent;
{
int cntlCode, axis;
int docV, docH;
int oldMWidth, newMWidth;
Point startPoint, endPoint;
ControlHandle theCtl, cHH, cHV;
MeterHandle theMeter;
Rect limitRect, slopRect;
startPoint = theEvent->where;
GlobalToLocal(&startPoint);
/* First handle scroll bar events... */
if ((cntlCode = FindControl(startPoint,theWindow,&theCtl)) != 0)
{
if (cntlCode >= inUpButton && cntlCode <= inPageDown) /* scroll, not thumb */
TrackControl(theCtl,startPoint,&ScrollProc);
else if (cntlCode == inThumb)
{
/* Ordinarily you would call TrackControl(theCtl,startPoint, 0L)
but today we're doing "real-time" thumb control. */
ThumbControl(theCtl, startPoint);
} /* else if in thumb */
} /* if in a control */
/* ...then handle "true content" mouse events. */
else
{
/* We're going to treat the meters as being attached to the
underlying document rather than the window frame, so we must shift to
"document" coordinates before determining which meter was hit. */
LocalToDoc(&startPoint);
if ((cntlCode = FindMeter(startPoint,theWindow,&theMeter)) != 0)
{
/* Shift everything to document coordinates before proceeding: */
/* 1 - get control handles */
GetScrollHandles(theWindow, &cHH, &cHV);
/* 2 - find where we've scrolled to */
docV = GetCtlValue(cHV);
docH = GetCtlValue(cHH);
/* 3 - shift to the right location in the document */
SetOrigin(docH, docV);
OffsetRgn(theWindow->clipRgn, docH, docV);
/* 4 - now deal with events as though no scrolling has
taken place */
if (theEvent->modifiers & optionKey)
{
/* Drag the meter around. This is very handy since meters take
up a lot of screen. Unneeded meters can be slid almost entirely
off the screen to make room for other things. */
slopRect = limitRect = thePort->portRect;
InsetRect(&limitRect, 10, 10);
limitRect.right -= SCROLLSIZE;
limitRect.bottom -=SCROLLSIZE;
axis = 0; /* no constraint */
DragMeter(theMeter, startPoint, &limitRect, &slopRect, axis);
}
else if (theEvent->modifiers & cmdKey)
{
/* Resize the meter while mouse down - useful when playing
with the look of the meter, and shows how the display box
can be a very handy design tool. */
oldMWidth = (**theMeter).meterRect.right - (**theMeter).meterRect.left;
while (StillDown())
{
GetMouse(&endPoint); /* still in unscrolled coord's */
newMWidth = oldMWidth - startPoint.h + endPoint.h;
SizeMeter(theMeter, newMWidth);
DrawDisplayBox(theWindow, (void**)theMeter, forMeter, 0,0);
}
}
else if (cntlCode >= inUpButton && cntlCode <= inPageDown) /* not background */
TrackMeter(theMeter,startPoint,&MeterProc);
else if (cntlCode == inBackground)
{
/* default for inBackGround just shows set point value */
TrackMeter(theMeter,startPoint,0L);
}
SetOrigin(0, 0);
OffsetRgn(theWindow->clipRgn, -docH, -docV);
} /* if FindMeter */
} /* else true content */
} /* end DoContent() */
/* The all-purpose redraw function, draws only what touches
the update region and handles scroll bars so that the routines
which draw individual items don't have to keep track of where
we've scrolled to in the document. Can even be used for printing,
provided you temporarily set the scroll bar values to the minimum
and the updateRgn to the whole document beforehand, and provided your
individual drawing routines don't set the port before drawing. */
void UpdateContents(wPtr, frontMost)
WindowPtr wPtr;
Boolean frontMost;
{
int docV, docH;
Rect clpRect;
ControlHandle cHH, cHV;
MeterHandle mH = (MeterHandle)(((WindowPeek)wPtr)->refCon);
SetClip(updateRgn);
/* get control handles */
GetScrollHandles(wPtr, &cHH, &cHV);
/* find where we've scrolled to */
docV = GetCtlValue(cHV);
docH = GetCtlValue(cHH);
/* shift to the right location in the document */
if (docV || docH)
{
SetOrigin(docH, docV);
OffsetRgn(wPtr->clipRgn, docH, docV);
}
/* we'll be ultra-efficient and draw only what
touches the updateRgn */
while (mH)
{
if (RectInRgn(&((**mH).meterRect), wPtr->clipRgn))
{
/* fool ShowMeter() into redrawing the meter */
(**mH).meterVis = FALSE;
ShowMeter(mH);
}
mH = (**mH).nextMeter;
}
if (docV || docH)
SetOrigin(0, 0);
clpRect.top = wPtr->portRect.top;
clpRect.left = wPtr->portRect.left;
clpRect.bottom = wPtr->portRect.bottom - SCROLLSIZE;
clpRect.right = wPtr->portRect.right - SCROLLSIZE;
ClipRect(&clpRect);
} /* end UpdateContents() */
/* Show two integer values in a little display box at bottom right
of the window. If you call this function with mode = forDebug, specify
the WindowPtr and put the two values in newValue and otherValue. */
void DrawDisplayBox(wPtr, theHandle, mode, newValue, otherValue)
WindowPtr wPtr;
void **theHandle;
DisplayMode mode;
int newValue, otherValue;
{
int i, j;
int oldFont, oldSize;
Style oldStyle;
long leftNum, rightNum;
char s[20], sr[10], *sPtr;
Rect displayRect, clpRect;
MeterHandle mH;
ControlHandle theCtl, cHH, cHV;
GrafPtr savePort;
if (DISPLAYBOXWIDTH <= 0) return;
GetPort(&savePort);
SetPort(wPtr);
oldFont = wPtr->txFont;
oldSize = wPtr->txSize;
oldStyle = wPtr->txFace; /* sic */
TextFont(0);
TextSize(12);
TextFace(' ');
displayRect.top = wPtr->portRect.bottom - SCROLLSIZE + 1;
displayRect.left = wPtr->portRect.right - DISPLAYBOXWIDTH -14;
displayRect.bottom = wPtr->portRect.bottom + 1;
displayRect.right = displayRect.left + DISPLAYBOXWIDTH - 1;
ClipRect(&displayRect);
EraseRect(&displayRect);
if (mode == forWindow)
{
GetScrollHandles(wPtr, &cHH, &cHV);
leftNum = (long)GetCtlValue(cHH);
rightNum = (long)GetCtlValue(cHV);
/* or
leftNum = wPtr->portRect.right - wPtr->portRect.left - 15;
rightNum = wPtr->portRect.bottom - wPtr->portRect.top - 15;
*/
}
else if (mode == forMeter)
{
mH = (MeterHandle)theHandle;
leftNum = (long)((**mH).meterRect.right - (**mH).meterRect.left);
rightNum = (long)((**mH).meterRect.bottom - (**mH).meterRect.top);
}
else if (mode == forThumb)
{
GetScrollHandles(wPtr, &cHH, &cHV);
theCtl = (ControlHandle)theHandle;
if (theCtl == cHH)
{
leftNum = (long)newValue;
rightNum = (long)GetCtlValue(cHV);
}
else
{
leftNum = (long)GetCtlValue(cHH);
rightNum = (long)newValue;
}
}
else if (mode == forDebug)
{
leftNum = (long)newValue;
rightNum = (long)otherValue;
}
else
{
leftNum = 0L;
rightNum = 0L;
}
NumToString(leftNum, s);
NumToString(rightNum, sr);
/* Concatenate sr into s with space between. */
j = s[0];
s[++j] = ' ';
for (i = 1, sPtr = &(s[j + 1]); i <= sr[0]; ++i)
*sPtr++ = sr[i];
s[0] += i; /* note 1 extra for space */
TextBox(&(s[1]), (Byte)(s[0]), &displayRect, teJustCenter);
clpRect.top = thePort->portRect.top;
clpRect.left = thePort->portRect.left;
clpRect.bottom = thePort->portRect.bottom - SCROLLSIZE;
clpRect.right = thePort->portRect.right - SCROLLSIZE;
ClipRect(&clpRect);
TextFont(oldFont);
TextSize(oldSize);
TextFace(oldStyle);
SetPort(savePort);
} /* end DrawDisplayBox() */
/* Both DoZoomWindow() and DoGrowWindow() handle the potentially
embarrassing problem of moving around in a document of fixed size
without scrolling out into the Twilight Zone. */
void DoZoomWindow (wPtr, part)
WindowPtr wPtr;
int part;
{
int oldV, oldH, newV, newH;
int vertRange, horRange;
int curValH, curMaxH, curValV, curMaxV;
Point dS;
ControlHandle cHH, cHV;
/* get control handles */
GetScrollHandles(wPtr, &cHH, &cHV);
oldV = (wPtr->portRect).bottom - (wPtr->portRect).top;
oldH = (wPtr->portRect).right - (wPtr->portRect).left;
curValH = GetCtlValue(cHH);
curMaxH = GetCtlMax(cHH);
curValV = GetCtlValue(cHV);
curMaxV = GetCtlMax(cHV);
ZoomWindow(wPtr, part, TRUE);
InvalRect(&(wPtr->portRect));
newV = (wPtr->portRect).bottom - (wPtr->portRect).top;
newH = (wPtr->portRect).right - (wPtr->portRect).left;
SetRect(&((**cHV).contrlRect), wPtr->portRect.right - SCROLLSIZE,
wPtr->portRect.top - 1, wPtr->portRect.right + 1,
wPtr->portRect.bottom - 14);
SetRect(&((**cHH).contrlRect), wPtr->portRect.left - 1,
wPtr->portRect.bottom - SCROLLSIZE, wPtr->portRect.right - DISPLAYBOXWIDTH - 14,
wPtr->portRect.bottom + 1);
vertRange = MAXWINDOWHEIGHT - (wPtr->portRect.bottom - wPtr->portRect.top);
vertRange = (vertRange > 0) ? vertRange : 0;
horRange = MAXWINDOWWIDTH - (wPtr->portRect.right - wPtr->portRect.left);
horRange = (horRange > 0) ? horRange : 0;
SetCtlMax(cHV, vertRange);
SetCtlMax(cHH, horRange);
if (vertRange == 0)
HiliteControl(cHV, 255);
else
HiliteControl(cHV, 0);
if (horRange == 0)
HiliteControl(cHH, 255);
else
HiliteControl(cHH, 0);
/* "Scroll" if running off the bottom or right. The whole window has
been invalidated above, so we just shift the scroll bars and
then let the update event take care of the redrawing later. */
/* dS.h(or .v) = overshoot = amount potentially exposed by zoom less
amount available to be exposed; potential amount = increase in
window size; amount available = maximum amount left unseen, which is
the (prezoom) control Max, less amount that has already scrolled by,
which is the (prezoom) control Value. If you grok that, you've got
scroll bars in the bag! */
dS.h = newH - oldH - curMaxH + curValH;
dS.h = (dS.h > 0) ? dS.h : 0;
dS.v = newV - oldV - curMaxV + curValV;
dS.v = (dS.v > 0) ? dS.v : 0;
if (dS.h > 0 || dS.v > 0)
{
SetCtlValue(cHV, GetCtlValue(cHV) - dS.v);
SetCtlValue(cHH, GetCtlValue(cHH) - dS.h);
}
} /* end DoZoomWindow() */
void DoGrowWindow(event)
EventRecord *event;
{
int winWidth, winHeight;
int horRange, vertRange;
int oldV, oldH, newV, newH;
int curValH, curMaxH, curValV, curMaxV;
long growResult;
Point dS;
Rect limitRect, badRect;
ControlHandle cHH, cHV;
RgnHandle tempRgn;
WindowPtr wPtr = FrontWindow();
winHeight = ((screenBits.bounds.bottom - screenBits.bounds.top - 22) <= MAXWINDOWHEIGHT) ?
(screenBits.bounds.bottom - screenBits.bounds.top - 22) : MAXWINDOWHEIGHT;
winWidth = ((screenBits.bounds.right - screenBits.bounds.left - 2) <= MAXWINDOWWIDTH) ?
(screenBits.bounds.right - screenBits.bounds.left - 2) : MAXWINDOWWIDTH;
limitRect.top = 130;
limitRect.left = 250;
limitRect.bottom = winHeight + 1;
limitRect.right = winWidth + 1;
/* get control handles */
GetScrollHandles(wPtr, &cHH, &cHV);
oldV = (wPtr->portRect).bottom - (wPtr->portRect).top;
oldH = (wPtr->portRect).right - (wPtr->portRect).left;
curValH = GetCtlValue(cHH);
curMaxH = GetCtlMax(cHH);
curValV = GetCtlValue(cHV);
curMaxV = GetCtlMax(cHV);
growResult = GrowWindow(wPtr, event->where, &limitRect);
newV = HiWord(growResult);
newH = LoWord(growResult);
SizeWindow(wPtr, newH, newV, TRUE);
ClipRect(&(wPtr->portRect));
SetRect(&((**cHV).contrlRect), wPtr->portRect.right - SCROLLSIZE,
wPtr->portRect.top - 1, wPtr->portRect.right + 1,
wPtr->portRect.bottom - 14);
SetRect(&((**cHH).contrlRect), wPtr->portRect.left - 1,
wPtr->portRect.bottom - SCROLLSIZE, wPtr->portRect.right - DISPLAYBOXWIDTH - 14,
wPtr->portRect.bottom + 1);
vertRange = MAXWINDOWHEIGHT - (wPtr->portRect.bottom - wPtr->portRect.top);
vertRange = (vertRange > 0) ? vertRange : 0;
horRange = MAXWINDOWWIDTH - (wPtr->portRect.right - wPtr->portRect.left);
horRange = (horRange > 0) ? horRange : 0;
SetCtlMax(cHV, vertRange);
SetCtlMax(cHH, horRange);
if (vertRange == 0)
HiliteControl(cHV, 255);
else
HiliteControl(cHV, 0);
if (horRange == 0)
HiliteControl(cHH, 255);
else
HiliteControl(cHH, 0);
/* update scroll bars properly */
if (newV > oldV)
{
badRect.top = oldV - SCROLLSIZE;
badRect.left = 0;
badRect.bottom = oldV;
badRect.right = oldH;
InvalRect(&badRect);
}
else
{
badRect.top = (wPtr->portRect).bottom - SCROLLSIZE;
badRect.left = (wPtr->portRect).left;
badRect.bottom = (wPtr->portRect).bottom;
badRect.right = (wPtr->portRect).right;
InvalRect(&badRect);
}
if (newH > oldH)
{
badRect.top = 0;
badRect.left = oldH - SCROLLSIZE;
badRect.bottom = oldV;
badRect.right = oldH;
InvalRect(&badRect);
}
else
{
badRect.top = (wPtr->portRect).top;
badRect.left = (wPtr->portRect).right - SCROLLSIZE;
badRect.bottom = (wPtr->portRect).bottom;
badRect.right = (wPtr->portRect).right;
InvalRect(&badRect);
}
badRect.top = (wPtr->portRect).top;
badRect.left = (wPtr->portRect).left;
badRect.bottom = (wPtr->portRect).bottom - SCROLLSIZE;
badRect.right = (wPtr->portRect).right - SCROLLSIZE;
/* Scroll if running off the bottom or right of document.
The newly exposed part is invalidated. The resulting
update event will set updateRgn equal to the total invalidated
region, and UpdateContents() will redraw only that part
of the window. */
dS.h = newH - oldH - curMaxH + curValH;
dS.h = (dS.h > 0) ? dS.h : 0;
dS.v = newV - oldV - curMaxV + curValV;
dS.v = (dS.v > 0) ? dS.v : 0;
if (dS.h > 0 || dS.v > 0)
{
ClipRect(&badRect);
tempRgn = NewRgn();
SetCtlValue(cHV, GetCtlValue(cHV) - dS.v);
SetCtlValue(cHH, GetCtlValue(cHH) - dS.h);
ScrollRect(&badRect, dS.h, dS.v, tempRgn);
InvalRgn(tempRgn);
DisposeRgn(tempRgn);
}
else
ClipRect(&badRect);
} /* end DoGrowWindow() */
void DoCloseWindow()
{
WindowPtr wPtr = FrontWindow();
KillMeters(wPtr);
CloseWindow(wPtr); /* does KillControls() for you */
} /* end DoCloseWindow() */
Boolean AMeterWindow(wPtr)
WindowPtr wPtr;
{
if (wPtr == (WindowPtr)(&wRecord1) || wPtr == (WindowPtr)(&wRecord2))
return(TRUE);
return(FALSE);
} /* end AMeterWindow() */
void GetScrollHandles(wPtr, cH, cV)
WindowPtr wPtr;
ControlHandle *cV, *cH;
{
ControlHandle cHH, cHV;
cHH = ((WindowPeek)wPtr)->controlList;
while (cHH)
{
if (GetCRefCon(cHH) == HSCROLL) break;
cHH = (**cHH).nextControl;
}
cHV = ((WindowPeek)wPtr)->controlList;
while (cHV)
{
if (GetCRefCon(cHV) == VSCROLL) break;
cHV = (**cHV).nextControl;
}
*cH = cHH;
*cV = cHV;
} /* end AMeterWindow() */
void LocalToDoc(thePt)
Point *thePt;
{
ControlHandle cHH, cHV;
/* get control handles */
GetScrollHandles(thePort, &cHH, &cHV);
/* Document coordinates are always at least as large
as local coord's - a mental picture of the window
sliding over the document helps.*/
thePt->v += GetCtlValue(cHV);
thePt->h += GetCtlValue(cHH);
} /* end LocalToDoc() */
void MeterProc(mH, theCode)
MeterHandle mH;
int theCode;
{
long posIncrement = ((**mH).meterMax - (**mH).meterMin)/250L;
long scrollAmt;
Delay(2L, &scrollAmt);
switch (theCode)
{
case inUpButton:
scrollAmt = posIncrement/10L;
if (!scrollAmt)
scrollAmt = 1L;
break;
case inDownButton:
scrollAmt = -posIncrement/10L;
if (!scrollAmt)
scrollAmt = -1L;
break;
case inPageUp:
scrollAmt = posIncrement;
break;
case inPageDown:
scrollAmt = -posIncrement;
break;
}
SetMtrValue(mH, GetMtrValue(mH) + scrollAmt);
} /* end MeterProc() */
pascal void ScrollProc(theCtl, partCode)
ControlHandle theCtl;
int partCode;
{
int delta, pageSize, arrowSize, oldValue;
Point dS;
Rect viewBnds;
Boolean horizontal = FALSE;
/* which control, how far */
if (GetCRefCon(theCtl) == HSCROLL)
{
horizontal = TRUE;
pageSize = (thePort->portRect).right - (thePort->portRect).left - SCROLLSIZE;
}
else /* VSCROLL */
pageSize = (thePort->portRect).bottom - (thePort->portRect).top - SCROLLSIZE;
arrowSize = pageSize/20;
/* delta is used to adjust local coord's, which DECREASE if
up button pressed (we move closer to top of document).
However, we want the stuff in the window to slide DOWN
so the sign of dS is reversed from that of delta in
order that ScrollRect() will work correctly. Hence for
up button of vertical scroll, delta is negative and
dS.v is positive (they agree in magnitude unless
we're at one end or the other of the document).*/
switch (partCode)
{
case inUpButton:
delta = -arrowSize;
break;
case inDownButton:
delta = arrowSize;
break;
case inPageUp:
delta = -pageSize;
break;
case inPageDown:
delta = pageSize;
break;
default:
delta = 0;
break;
} /* end switch */
ClipRect(&(thePort->portRect));
oldValue = GetCtlValue(theCtl);
SetCtlValue(theCtl, oldValue + delta);
if (horizontal)
{
dS.h = oldValue - GetCtlValue(theCtl);
dS.v = 0;
}
else /* vertical */
{
dS.v = oldValue - GetCtlValue(theCtl);
dS.h = 0;
}
viewBnds.top = (thePort->portRect).top;
viewBnds.left = (thePort->portRect).left;
viewBnds.bottom = (thePort->portRect).bottom - SCROLLSIZE;
viewBnds.right = (thePort->portRect).right - SCROLLSIZE;
ScrollRect(&viewBnds, dS.h, dS.v, updateRgn);
DrawDisplayBox(thePort, 0L, forWindow, 0,0);
UpdateContents(thePort, TRUE);
} /* end ScrollProc() */
/* This function will track the mouse and correctly update the value of a scroll bar as the
thumb is dragged around, in case you might want to update a graphic or number continuously
as the user moves the thumb about, something TrackControl() doesn't readily allow. Use
"ThumbControl(startPoint, theCtl);" in place of "if (TrackControl(theCtl,startPoint, 0L))"
when FindControl() reports an appropriate thumb event, and modify the action calls in this
routine where indicated. Depending on your needs, you may want to clip differently. For
generality, this routine decides which scroll bar is which by the same method that the
Control Manager uses - which way is longer? Much of "while (StillDown())" below is a
duplication of DragGrayRgn() that lets us tell where we are at all times.
*/
void ThumbControl(theCtl, startPoint)
ControlHandle theCtl;
Point startPoint;
{
int newValue, startValue, thickness;
int mouseRange, controlMin, controlMax;
long thumbRange, controlRange;
Point theMouse, thumbStart, thumbMin, thumbMax, newThumbCent, thumbCent, halfThumb;
Rect controlRect,slopRect, startRect, thumbRect;
RgnHandle oldClipRgn;
PenState pState;
Boolean isHorizontalBar, tracking;
GetPenState(&pState);
PenMode(patXor);
PenPat(dkGray);
PenSize(1,1);
controlRect = (**theCtl).contrlRect;
slopRect = controlRect;
controlMin = GetCtlMin(theCtl);
controlMax = GetCtlMax(theCtl);
controlRange = (long)(controlMax - controlMin);
startValue = GetCtlValue(theCtl);
newValue = startValue;
isHorizontalBar = (controlRect.right - controlRect.left) >
(controlRect.bottom - controlRect.top) ? TRUE : FALSE;
if (isHorizontalBar)
{
thumbStart.v = controlRect.top + (controlRect.bottom - controlRect.top + 1)/2;
thumbMin.v = thumbMax.v = thumbStart.v;
thickness = controlRect.bottom - controlRect.top;
halfThumb.h = thickness/2;
halfThumb.v = halfThumb.h - 1;
thumbMin.h = controlRect.left + thickness + (thickness + 1)/2;
thumbMax.h = controlRect.right - thickness - (thickness + 1)/2;
thumbRange = (long)(controlRect.right - controlRect.left - 3*thickness);
thumbStart.h = thumbMin.h + (thumbRange*(startValue - controlMin) + controlRange/2)/controlRange;
InsetRect(&slopRect, -72, -36);
}
else
{
thumbStart.h = controlRect.left + (controlRect.right - controlRect.left + 1)/2;
thumbMin.h = thumbMax.h = thumbStart.h;
thickness = controlRect.right - controlRect.left;
halfThumb.v = thickness/2;
halfThumb.h = halfThumb.v - 1;
thumbMin.v = controlRect.top + thickness + (thickness + 1)/2;
thumbMax.v = controlRect.bottom - thickness - (thickness + 1)/2;
thumbRange = (long)(controlRect.bottom - controlRect.top - 3*thickness);
thumbStart.v = thumbMin.v + (thumbRange*(startValue - controlMin) + controlRange/2)/controlRange;
InsetRect(&slopRect, -36, -72);
}
if (thumbRange <= 0) return; /* that's a pretty short scroll bar */
newThumbCent = thumbCent = thumbStart;
oldClipRgn = NewRgn();
GetClip(oldClipRgn);
ClipRect(&controlRect);
SetRect(&thumbRect, thumbCent.h - halfThumb.h, thumbCent.v - halfThumb.v,
thumbCent.h + halfThumb.h, thumbCent.v + halfThumb.v);
tracking = FALSE;
while (StillDown())
{
ClipRect(&controlRect);
GetMouse(&theMouse);
if (PtInRect(theMouse, &slopRect))
{ /* mouse is close to scroll bar - track the thumb */
/* calculate new thumb center */
if (isHorizontalBar)
{
newThumbCent.h = thumbStart.h + (theMouse.h - startPoint.h);
if (newThumbCent.h < thumbMin.h)
newThumbCent.h = thumbMin.h;
else if (newThumbCent.h > thumbMax.h)
newThumbCent.h = thumbMax.h;
}
else
{
newThumbCent.v = thumbStart.v + (theMouse.v - startPoint.v);
if (newThumbCent.v < thumbMin.v)
newThumbCent.v = thumbMin.v;
else if (newThumbCent.v > thumbMax.v)
newThumbCent.v = thumbMax.v;
}
if (tracking)
{
if (newThumbCent.h != thumbCent.h || newThumbCent.v != thumbCent.v)
{
FrameRect(&thumbRect);
SetRect(&thumbRect, newThumbCent.h - halfThumb.h, newThumbCent.v - halfThumb.v,
newThumbCent.h + halfThumb.h, newThumbCent.v + halfThumb.v);
FrameRect(&thumbRect);
}
}
else /* just entering slop rect */
{
SetRect(&thumbRect, newThumbCent.h - halfThumb.h, newThumbCent.v - halfThumb.v,
newThumbCent.h + halfThumb.h, newThumbCent.v + halfThumb.v);
FrameRect(&thumbRect);
tracking = TRUE;
}
} /* if track the thumb */
else /* not in slop rect */
{
if (tracking)
{ /* just leaving slop rect */
FrameRect(&thumbRect);
tracking = FALSE;
newThumbCent = thumbStart;
}
} /* else default to start position */
if (newThumbCent.h != thumbCent.h || newThumbCent.v != thumbCent.v)
{
/* Either thumb has been dragged to new position or mouse has left
slopRect, in which case thumbCent reverts to thumbStart. */
/* Calculate control value based on newThumbCent. */
newValue = (controlRange*(newThumbCent.h - thumbMin.h
+ newThumbCent.v - thumbMin.v) + thumbRange/2)/thumbRange + controlMin;
thumbCent = newThumbCent;
/*************************************************************************/
/* Insert your custom call here - the current control value is "newValue";
reset the clipRgn if you draw outside the scroll bar!*/
/* Sample thumb action; echo control values to display box. */
DrawDisplayBox(thePort, (void**)theCtl, forThumb, newValue,0);
/*************************************************************************/
}
} /* while still down */
if (tracking)
FrameRect(&thumbRect);
if (newValue != startValue)
{
SetCtlValue(theCtl, newValue);
/* The control value has changed on mouseup to "newValue" - take
appropriate action - here we redraw the window */
InvalRect(&(thePort->portRect));
}
else
{
/* the control value hasn't changed - reset if necessary */;
}
SetClip(oldClipRgn);
DisposeRgn(oldClipRgn);
SetPenState(&pState);
} /* end ThumbControl() */
void PutMetersOnClip(wPtr)
WindowPtr wPtr;
{
Rect theClipRect;
PicHandle clipPicH;
RgnHandle oldClipRgn;
MeterHandle mH = (MeterHandle)(((WindowPeek)wPtr)->refCon);
ZeroScrap();
theClipRect.top = 0;
theClipRect.left = 0;
theClipRect.bottom = DOCHEIGHT;
theClipRect.right = DOCWIDTH;
oldClipRgn = NewRgn();
GetClip(oldClipRgn);
ClipRect(&theClipRect);
/* draw the picture */
clipPicH = OpenPicture(&theClipRect);
while (ValidMeter(mH))
{
MeterSnapshot(mH);
mH = (**mH).nextMeter;
}
ClosePicture();
/* put it on the scrap and clean up */
HLock(clipPicH);
PutScrap(GetHandleSize(clipPicH), 'PICT', *clipPicH);
HUnlock(clipPicH);
KillPicture(clipPicH);
SetClip(oldClipRgn);
DisposeRgn(oldClipRgn);
} /* end PutMetersOnClip() */
/* End MeterMain.c */